<template>
  <div class="meeting-webview-page">
    <div class="webview-wrapper">
      <div ref="jitsiContainer" class="jitsi-container"></div>
      <el-drawer
        v-model="sidebarOpen"
        direction="rtl"
        size="320px"
        :with-header="true"
        :close-on-click-modal="true"
        :destroy-on-close="false"
      >
        <template #header>
          <div class="drawer-header">
            <span class="title">会议文件</span>
            <el-upload
              ref="meetingUploadRef"
              class="upload-item"
              action=""
              :show-file-list="false"
              :auto-upload="false"
              :before-upload="beforeMeetingFileUpload"
              @change="handleMeetingFileSelected"
            >
              <el-button type="primary" size="small">上传文件</el-button>
            </el-upload>
          </div>
        </template>
        <el-image-viewer
          v-if="imagePreviewVisible"
          :url-list="imagePreviewUrls"
          @close="imagePreviewVisible = false"
        />
        <div class="file-list" v-loading="fileLoading">
          <template v-if="meetingFiles.length">
            <div class="file-item" v-for="file in meetingFiles" :key="file.id || file.fileUrl">
              <div class="file-meta">
                <div class="meta-line file-name">{{ file.fileName || getFileName(file.fileUrl) }}</div>
                <div class="meta-line size-line">大小：{{ formatFileSize(file.fileSize) }}</div>
                <div class="meta-line uploader-line">上传者：{{ file.uploaderUsername || file.createUserName || '未知上传者' }}</div>
              </div>
              <div class="file-ops">
                <el-button v-if="isImage(file)" text size="small" :icon="View" @click="previewImage(file)"></el-button>
                <el-button text size="small" :icon="Download" @click="downloadMeetingFile(file)"></el-button>
                <el-button v-if="canDeleteFile(file)" text size="small" type="danger" :icon="Delete" @click="deleteMeetingFileItem(file)"></el-button>
              </div>
            </div>
          </template>
          <div v-else class="empty-tip">暂无文件</div>
        </div>
      </el-drawer>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Download, Delete, View } from '@element-plus/icons-vue'
import { getUserInfo } from '@/utils/webStorage'
import { postUploadFile } from '@/axios/api/upload'
import { getMeetingFileList, postSaveMeetingFile, deleteMeetingFile as apiDeleteMeetingFile } from '@/axios/api/meeting'

// 路由
const route = useRoute()
const router = useRouter()

// Reactive data
const currentUser = ref(getUserInfo() || {})
const jitsiContainer = ref(null)
let jitsiApi = null
const meeting = ref(null)

// 文件侧边栏与列表状态
const sidebarOpen = ref(false)
const meetingFiles = ref([])
const fileLoading = ref(false)
const meetingUploadRef = ref(null)
let filePoller = null

// 录制相关状态
const recording = ref(false)
const recordingChunks = []
let mediaRecorder = null
let displayStream = null
let recordingStartAt = 0
let recordingTimer = null
const recordingDurationText = ref('00:00')
let fileWritable = null // File System Access API 的写入句柄（支持时）

// ====== 会议文件侧边栏逻辑 ======
function isImage(file) {
  const url = file?.fileUrl || ''
  const type = file?.fileType || ''
  if (type && typeof type === 'string') {
    if (type.startsWith('image/')) return true
  }
  const lower = url.toLowerCase()
  return ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'].some(ext => lower.endsWith(ext))
}

function getFileName(url) {
  try {
    const u = new URL(url)
    const pathname = u.pathname
    return pathname.substring(pathname.lastIndexOf('/') + 1)
  } catch (e) {
    return (url || '').substring((url || '').lastIndexOf('/') + 1)
  }
}

function formatFileSize(bytes) {
  if (!bytes && bytes !== 0) return ''
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  const val = (bytes / Math.pow(k, i)).toFixed(i === 0 ? 0 : 2)
  return `${val} ${sizes[i]}`
}

// 显示图片预览查看器
const imagePreviewVisible = ref(false)
const imagePreviewUrls = ref([])
function previewImage(file) {
  const url = file?.fileUrl
  if (!url) return
  imagePreviewUrls.value = [url]
  imagePreviewVisible.value = true
}

function beforeMeetingFileUpload(file) {
  const max = 100 * 1024 * 1024 // 100MB
  if (file.size > max) {
    ElMessage.error('文件大小不能超过100MB')
    return false
  }
  return true
}

async function handleMeetingFileSelected(file) {
  try {
    if (!beforeMeetingFileUpload(file)) return false
    const formData = new FormData()
    formData.append('Image', file.raw)
    const data = await postUploadFile(formData)
    const uploadedUrl = data?.result

    console.log(uploadedUrl)
    if (!uploadedUrl) {
      ElMessage.error('上传失败')
      return false
    }

    const fileType = file.raw?.type || ''
    const params = {
      meetingId: meeting.value?.id,
      fileName: file.name,
      fileUrl: uploadedUrl,
      fileSize: file.size,
      fileType,
      uploaderUid: currentUser.value?.uid || '',
      uploaderUsername: currentUser.value?.username || currentUser.value?.name || ''
    }
    const saveRes = await postSaveMeetingFile(params)
    if (saveRes?.code === 0) {
      ElMessage.success('文件已保存到会议')
      meetingUploadRef.value?.clearFiles?.()
      await fetchMeetingFiles()
    } else {
      ElMessage.error(saveRes?.message || '保存会议文件失败')
    }
    return false
  } catch (e) {
    console.error('会议文件上传失败:', e)
    ElMessage.error('会议文件上传失败')
    return false
  }
}

async function fetchMeetingFiles() {
  if (!meeting.value?.id) return
  if (fileLoading.value) return
  fileLoading.value = true
  try {
    const res = await getMeetingFileList({ meetingId: meeting.value.id, page: 1, limit: 50 })
    // 兼容不同返回结构
    const list = res?.result?.data || res?.result || res?.data || []
    meetingFiles.value = Array.isArray(list) ? list : []
  } catch (e) {
    console.error('获取会议文件列表失败:', e)
  } finally {
    fileLoading.value = false
  }
}

function startFilePolling() {
  stopFilePolling()
  filePoller = setInterval(fetchMeetingFiles, 5000)
}

function stopFilePolling() {
  if (filePoller) {
    clearInterval(filePoller)
    filePoller = null
  }
}

function downloadMeetingFile(file) {
  try {
    const fileUrl = file?.fileUrl
    const fileName = file?.fileName || getFileName(fileUrl)
    const link = document.createElement('a')
    link.href = fileUrl
    link.download = fileName
    link.target = '_blank'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  } catch (e) {
    console.error('下载失败:', e)
    ElMessage.error('下载文件失败')
  }
}

async function deleteMeetingFileItem(file) {
  try {
    if (!canDeleteFile(file)) {
      ElMessage.warning('仅可删除本人上传的文件')
      return
    }
    await ElMessageBox.confirm('确定删除该文件？该操作不可恢复', '提示', {
      confirmButtonText: '删除',
      cancelButtonText: '取消',
      type: 'warning',
    })
    const fileId = file?.id || file?.fileId
    const params = fileId ? { fileId, meetingId: meeting.value?.id } : { meetingId: meeting.value?.id, fileName: file?.fileName }
    const res = await apiDeleteMeetingFile(params)
    if (res?.code === 0) {
      ElMessage.success('删除成功')
      await fetchMeetingFiles()
    } else {
      ElMessage.error(res?.message || '删除失败')
    }
  } catch (e) {
    if (e === 'cancel') return
    console.error('删除会议文件失败:', e)
    ElMessage.error('删除会议文件失败')
  }
}

// 仅允许本人删除自己的文件
function canDeleteFile(file) {
  const myUid = currentUser.value?.uid || currentUser.value?.id
  const ownerUid = file?.uploaderUid ?? file?.createUid ?? file?.createUserId ?? file?.uid ?? file?.userId
  if (!myUid || !ownerUid) return false
  return String(myUid) === String(ownerUid)
}

// 开始本地录制（优先边录边写到磁盘）
async function startLocalRecording() {
  // 开始前确认磁盘空间提示，确认后继续执行下方功能
  try {
    await ElMessageBox.confirm('请确保有足够磁盘空间，以满足录屏文件存储需求。', '录屏提示', {
      confirmButtonText: '继续录制',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch (e) {
    // 用户取消，不继续执行后续录制流程
    return
  }
  try {
    // 若支持 File System Access API，预先选择保存位置并创建写入句柄
    fileWritable = null
    const defaultName = `meeting-${meeting.value?.id || 'room'}-${new Date().toISOString().replace(/[:.]/g, '-')}.webm`
    if (window.showSaveFilePicker) {
      try {
        const handle = await window.showSaveFilePicker({
          suggestedName: defaultName,
          types: [{ description: 'WebM Video', accept: { 'video/webm': ['.webm'] } }]
        })
        fileWritable = await handle.createWritable()
      } catch (pickerErr) {
        // 用户取消或失败，回退到内存累积模式
        fileWritable = null
      }
    }

    // 捕获屏幕/标签页与音频
    displayStream = await navigator.mediaDevices.getDisplayMedia({
      video: { frameRate: 30 },
      audio: true
    })

    const options = { mimeType: 'video/webm;codecs=vp9,opus' }
    mediaRecorder = new MediaRecorder(displayStream, options)
    recordingChunks.length = 0

    mediaRecorder.ondataavailable = async (e) => {
      try {
        if (e && e.data && e.data.size > 0) {
        if (fileWritable) {
          // 边录边写，避免内存累积
          await fileWritable.write(e.data)
        } else {
          // 回退：内存累积块，结束后统一保存
          recordingChunks.push(e.data)
        }
        }
      } catch (writeErr) {
        console.error('写入录制数据失败:', writeErr)
        ElMessage.error(`写入失败：${writeErr?.message || writeErr}`)
      }
    }
    mediaRecorder.onstop = async () => {
      try {
        if (fileWritable) {
          await fileWritable.close()
          fileWritable = null
          ElMessage.success('录制文件已保存')
        } else {
          await saveRecording()
        }
      } catch (finalizeErr) {
        console.error('保存录制失败:', finalizeErr)
        ElMessage.error(`保存录制失败：${finalizeErr?.message || finalizeErr}`)
      } finally {
        // 确保外部停止（例如浏览器停止共享）时也同步按钮与计时状态
        recording.value = false
        stopDurationTimer()
        syncToolbarRecordingToggle()
      }
    }

    mediaRecorder.start(1000) // 每秒一个块，减小单块体积
    recording.value = true
    recordingStartAt = Date.now()
    startDurationTimer()

    // 监听浏览器层面的共享停止事件（例如点击“停止共享”）
    try {
      displayStream?.addEventListener?.('inactive', onDisplayStreamInactive)
      displayStream?.getTracks()?.forEach(t => t?.addEventListener?.('ended', onDisplayStreamInactive))
    } catch (e) {
      // 兼容性容错
    }

    // 同步工具栏按钮为“录制中”状态（高亮/切换）
    syncToolbarRecordingToggle()
  } catch (e) {
    console.error('开始录制失败:', e)
    ElMessage.error(`开始录制失败：${e?.message || e}`)
  }
}

function stopLocalRecording() {
  try {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
      mediaRecorder.stop()
    }
  } catch (e) {
    console.warn('停止录制异常:', e)
  } finally {
    recording.value = false
    stopDurationTimer()
    stopStream(displayStream)
    displayStream = null
    // 同步工具栏按钮为“未录制”状态
    syncToolbarRecordingToggle()
  }
}

async function saveRecording() {
  try {
    const blob = new Blob(recordingChunks, { type: 'video/webm' })
    const defaultName = `meeting-${meeting.value?.id || 'room'}-${new Date().toISOString().replace(/[:.]/g, '-')}.webm`

    if (window.showSaveFilePicker) {
      const handle = await window.showSaveFilePicker({
        suggestedName: defaultName,
        types: [{ description: 'WebM Video', accept: { 'video/webm': ['.webm'] } }]
      })
      const writable = await handle.createWritable()
      await writable.write(blob)
      await writable.close()
      ElMessage.success('录制文件已保存')
    } else {
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = defaultName
      a.click()
      setTimeout(() => URL.revokeObjectURL(url), 3000)
      ElMessage.success('录制文件已下载')
    }
  } catch (e) {
    console.error('保存录制失败:', e)
    ElMessage.error(`保存录制失败：${e?.message || e}`)
  }
}

function startDurationTimer() {
  stopDurationTimer()
  recordingTimer = setInterval(() => {
    const s = Math.floor((Date.now() - recordingStartAt) / 1000)
    const mm = String(Math.floor(s / 60)).padStart(2, '0')
    const ss = String(s % 60).padStart(2, '0')
    recordingDurationText.value = `${mm}:${ss}`
  }, 1000)
}

function stopDurationTimer() {
  if (recordingTimer) {
    clearInterval(recordingTimer)
    recordingTimer = null
  }
  recordingDurationText.value = '00:00'
}

// 当浏览器层面停止了屏幕共享（用户点击了浏览器控件）
function onDisplayStreamInactive() {
  try {
    if (recording.value) {
      recording.value = false
      stopDurationTimer()
      syncToolbarRecordingToggle()
    }
  } catch (e) {}
}

// 同步 Jitsi 工具栏自定义按钮的切换状态（若支持）
function syncToolbarRecordingToggle() {
  try {
    if (jitsiApi && typeof jitsiApi.executeCommand === 'function') {
      jitsiApi.executeCommand('setToolbarButtonToggled', { key: 'local-record', toggled: !!recording.value })
    }
  } catch (e) {
    // 某些版本可能不支持 setToolbarButtonToggled，忽略错误即可
  }
}

function stopStream(stream) {
  try {
    stream?.getTracks()?.forEach(t => t.stop())
  } catch (e) {}
}

function stopRecordingIfNeeded() {
  try {
    if (recording.value) {
      stopLocalRecording()
    }
  } catch (e) {}
}

function getConfig() {
  const cfg = (window && window.config_global) || {}
  // 优先使用显式的 external_api 地址，其次用域名拼接，最后走 meet.jit.si
  const domain = cfg.JITSI_DOMAIN || 'meet.jit.si'
  const externalApi = cfg.JITSI_EXTERNAL_API || `https://${domain}/external_api.js`
  return { domain, externalApi }
}

function loadJitsiScript(src) {
  return new Promise((resolve, reject) => {
    // 如果已加载则跳过
    if (window.JitsiMeetExternalAPI) return resolve()
    const script = document.createElement('script')
    script.src = src
    script.async = true
    script.onload = () => resolve()
    script.onerror = (e) => reject(e)
    document.head.appendChild(script)
  })
}

async function initJitsi() {
  try {
    const { domain, externalApi } = getConfig()
    await loadJitsiScript(externalApi)
    await nextTick()
    if (!jitsiContainer.value) return
    // 若已存在实例，先销毁
    if (jitsiApi && jitsiApi.dispose) {
      jitsiApi.dispose()
      jitsiApi = null
    }

    const roomName = meeting.value?.roomId || meeting.value?.id || 'test-room'
    const displayName = currentUser.value?.name || currentUser.value?.username || '用户'

    jitsiApi = new window.JitsiMeetExternalAPI(domain, {
      roomName,
      parentNode: jitsiContainer.value,
      userInfo: { displayName },
      width: '100%',
      height: '100%',
      lang: 'zh-CN',
      // 基本配置
      useOriginalRoomName: true, // 直接会议使用原始房间名，确保相同room参数的用户能加入同一会议

      // 功能配置覆盖
      configOverwrite: {
        // Controls the visibility and behavior of the top header conference info labels.
        // If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
        conferenceInfo: {
          // those labels will not be hidden in tandem with the toolbox.
          alwaysVisible: ['recording', 'raised-hands-count'],
          // those labels will be auto-hidden in tandem with the toolbox buttons.
          autoHide: [
            // 'subject',
            // 'conference-timer',
            // 'participants-count',
            // 'e2ee',
            // 'video-quality',
            // 'insecure-room',
            // 'highlight-moment',
            // 'top-panel-toggle',
            // 'videoquality',
          ]
        },

        // 音频视频相关
        startWithAudioMuted: false, // 加入会议时是否默认关闭麦克风
        startWithVideoMuted: false, // 直接会议默认开启视频

        // 用户信息相关
        requireDisplayName: false, // 是否需要显示名称

        // 页面显示相关
        prejoinPageEnabled: false, // 是否启用预加入页面
        enableWelcomePage: false, // 是否启用欢迎页面
        enablePrejoinPage: false, // 是否启用预加入页面（重复配置）
        enableClosePage: false, // 是否启用会议结束页面

        // 安全相关
        enableUserRolesBasedOnToken: false, // 是否基于令牌启用用户角色
        enableInsecureRoomNameWarning: false, // 是否启用不安全房间名警告
        disableDeepLinking: true, // 是否禁用深度链接
        enableRoomPasswordProtection: false, // 是否启用房间密码保护
        disableRoomPassword: true, // 是否禁用房间密码
        enableGuestsAccess: true, // 是否启用访客访问
        enableLobby: false, // 是否启用 lobby 功能（等候室）

        // 其他功能配置
        disableModeratorIndicator: false, // 是否禁用主持人指示器
        startScreenSharing: false, // 是否自动开始屏幕共享
        enableEmailInStats: true, // 是否在统计信息中启用电子邮件
        enableAutomaticUrlDisplay: false, // 是否自动显示 URL
        disableChatSmileys: true, // 是否禁用聊天笑脸
        disableReactions: true, // 是否禁用聊天反应

        disabledSounds: [
          'ASKED_TO_UNMUTE_SOUND',
          'E2EE_OFF_SOUND',
          'E2EE_ON_SOUND',
          'INCOMING_MSG_SOUND',
          'KNOCKING_PARTICIPANT_SOUND',
          'LIVE_STREAMING_OFF_SOUND',
          'LIVE_STREAMING_ON_SOUND',
          'NO_AUDIO_SIGNAL_SOUND',
          'NOISY_AUDIO_INPUT_SOUND',
          'OUTGOING_CALL_EXPIRED_SOUND',
          'OUTGOING_CALL_REJECTED_SOUND',
          'OUTGOING_CALL_RINGING_SOUND',
          'OUTGOING_CALL_START_SOUND',
          'PARTICIPANT_JOINED_SOUND',
          'PARTICIPANT_LEFT_SOUND',
          'RAISE_HAND_SOUND',
          'REACTION_SOUND',
          'RECORDING_OFF_SOUND',
          'RECORDING_ON_SOUND',
          'TALK_WHILE_MUTED_SOUND',
        ],

        // 启用更多功能
        enableChat: true, // 启用聊天功能
        enableRecording: true, // 启用录制功能
        enableLiveStreaming: true, // 启用直播功能
        enableFileRecordingsSharing: true, // 启用文件录制共享
        enableRemoteVideoMenu: true, // 启用远程视频菜单
        disableRemoteMute: false, // 是否禁用远程静音
        enableFeaturesBasedOnToken: false, // 是否基于令牌启用功能

        customToolbarButtons: [
          {
            icon: "",
            id: "custom-toolbar-button",
            text: "共享文件",
          },
          {
            icon: "",
            id: "local-record",
            text: "本地录制",
          },
        ],
        buttonsWithNotifyClick: [
          "custom-toolbar-button",
          "local-record",
          { key: "hangup", preventExecution: false },
          { key: "end-meeting", preventExecution: false }
        ],
      },

      // 界面配置覆盖
      interfaceConfigOverwrite: {
        // 工具栏按钮配置（当前为空数组，表示不显示任何工具栏按钮）
        TOOLBAR_BUTTONS: [
          'camera',
          'chat',
          'closedcaptions',
          'desktop',
          'download',
          // 'embedmeeting',
          'etherpad',
          'feedback',
          'filmstrip',
          'fullscreen',
          'hangup',
          'help',
          'highlight',
          // 'invite',
          'linktosalesforce',
          'livestreaming',
          'microphone',
          // 'noisesuppression',
          'participants-pane',
          'profile',
          'raisehand',
          // 'security',
          // 'select-background',
          'settings',
          // 'shareaudio',
          // 'sharedvideo',
          // 'shortcuts',
          // 'stats',
          'tileview',
          'toggle-camera',
          // 'videoquality',
          // 'whiteboard',
        ],

        // 页面显示配置
        ENABLE_PREJOIN_PAGE: false, // 是否启用预加入页面

        // 设置项配置
        SETTINGS_SECTIONS: ['devices', 'language', 'moderator', 'profile', 'calendar'], // 设置页面显示的部分

        // 水印相关配置
        SHOW_JITSI_WATERMARK: false, // 是否显示 Jitsi 水印
        SHOW_WATERMARK_FOR_GUESTS: false, // 是否为访客显示水印
        SHOW_BRAND_WATERMARK: false, // 是否显示品牌水印
        BRAND_WATERMARK_LINK: "", // 品牌水印链接
        SHOW_POWERED_BY: false, // 是否显示技术支持信息

        // 促销相关配置
        SHOW_PROMOTIONAL_CLOSE_PAGE: false, // 是否显示促销关闭页面
        SHOW_CHROME_EXTENSION_BANNER: false, // 是否显示 Chrome 扩展横幅
        MOBILE_APP_PROMO: false, // 是否显示移动应用促销

        // 界面元素配置
        FILMSTRIP_ENABLED: true, // 是否启用胶片条（参与者缩略图列表）
        GENERATE_ROOMNAMES_ON_WELCOME_PAGE: false, // 是否在欢迎页面生成房间名
        DISPLAY_WELCOME_PAGE_CONTENT: false, // 是否显示欢迎页面内容
        DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false, // 是否显示欢迎页面工具栏附加内容

        // 应用名称配置
        APP_NAME: '音视频会议', // 应用名称

        // 邀请功能配置
        HIDE_INVITE_MORE_HEADER: false, // 是否隐藏更多邀请头部

        // 动画效果配置
        ENABLE_FEEDBACK_ANIMATION: true, // 是否启用反馈动画
        ENABLE_JOIN_LEAVE_ANIMATIONS: true, // 是否启用加入/离开动画

        // 状态指示器配置
        DISABLE_PRESENCE_STATUS: false, // 是否禁用在线状态
        DISABLE_FOCUS_INDICATOR: false, // 是否禁用焦点指示器
        DISABLE_DOMINANT_SPEAKER_INDICATOR: false, // 是否禁用主导说话者指示器
      }
    })

    // 监听会议结束（用户离开房间）
    jitsiApi.addEventListener('readyToClose', () => {
      handleClose()
    })

    // 监听工具栏按钮点击（用于本地录制及会议文件按钮）
    jitsiApi.addEventListener('toolbarButtonClicked', (payload) => {
      const key = payload?.key
      if (key === 'local-record') {
        if (!recording.value) {
          startLocalRecording()
        } else {
          stopLocalRecording()
        }
  } else if (key === 'custom-toolbar-button') {
        // 切换会议文件抽屉显隐
        sidebarOpen.value = !sidebarOpen.value
        try {
          jitsiApi.executeCommand('setToolbarButtonToggled', { key: 'custom-toolbar-button', toggled: !!sidebarOpen.value })
        } catch (e) {}
        if (sidebarOpen.value) {
          fetchMeetingFiles()
          startFilePolling()
        } else {
          stopFilePolling()
        }
      } else if (key === 'hangup' || key === 'end-meeting') {
        // 挂断或结束会议后执行清理（默认 Jitsi 也会触发 readyToClose）
        // 这里作为兜底处理，确保页面返回
        // handleClose() // 可选：通常不需要此处手动调用
      }
    })
  } catch (err) {
    console.error('初始化 Jitsi 失败: ', err)
  }
}

function disposeJitsi() {
  try {
    if (jitsiApi && jitsiApi.dispose) {
      jitsiApi.dispose()
      jitsiApi = null
    }
  } catch (e) {
    console.warn('销毁 Jitsi 出错: ', e)
  }
}

// Methods
const handleClose = () => {
  disposeJitsi()
  stopRecordingIfNeeded()
  // 返回上一页或会议列表
  if (window.history.length > 1) {
    router.back()
  } else {
    router.push('/meeting')
  }
}

// 顶栏已移除，返回逻辑由 Jitsi 的“挂断”按钮触发

// 初始化会议数据并加载 Jitsi
onMounted(() => {
  currentUser.value = getUserInfo() || {}
  const q = route.query || {}
  meeting.value = {
    id: q.id || q.meetingId || 'test-room',
    roomId: q.roomId || q.id || q.meetingId || 'test-room',
    title: q.title || 'test-room'
  }
  initJitsi()
})

// 抽屉显隐联动：打开时拉取并轮询，关闭时停止轮询，同时同步工具栏按钮状态
watch(() => sidebarOpen.value, (open) => {
  try {
    if (jitsiApi && typeof jitsiApi.executeCommand === 'function') {
      jitsiApi.executeCommand('setToolbarButtonToggled', { key: 'custom-toolbar-button', toggled: !!open })
    }
  } catch (e) {}

  if (open) {
    fetchMeetingFiles()
    startFilePolling()
  } else {
    stopFilePolling()
  }
})

onBeforeUnmount(() => {
  disposeJitsi()
  stopRecordingIfNeeded()
  stopFilePolling()
})
</script>

<style scoped>
.meeting-webview-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-bottom: 1px solid #eee;
}
.header-title {
  font-weight: 700;
  font-size: 16px;
}
.webview-wrapper {
  flex: 1;
  display: flex;
  min-height: 0;
}
.jitsi-container {
  flex: 1;
  width: 100%;
  height: 100%;
  min-height: 0;
}
.file-sidebar {
  width: 420px;
  border-left: 1px solid #eee;
  background: #fafafa;
  display: flex;
  flex-direction: column;
}
.file-sidebar.hidden {
  display: none;
}
.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  border-bottom: 1px solid #eee;
}
.sidebar-header .title {
  font-weight: 600;
}
.file-list {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  margin-top: 8px;
  border-top: 1px solid #eee;
}
.file-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 0;
  border-bottom: 1px solid #eee;
}
.file-item:last-child { border-bottom: none; }
.drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;

}
.drawer-header .title { font-weight: 600; }
.file-thumb {
  display: flex;
  align-items: center;
  gap: 8px;
}
.file-meta {
  flex: 1 1 auto;
  min-width: 0;
  margin-left: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.file-meta .file-name {
  color: #333;
  font-size: 13px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-meta .size-line,
.file-meta .uploader-line {
  color: #666;
  font-size: 12px;
}
.file-thumb .el-image {
  width: 48px;
  height: 48px;
  border-radius: 4px;
  overflow: hidden;
}
.file-generic .name {
  font-size: 12px;
  color: #606266;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-ops {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  flex: 0 0 auto;
}
.empty-tip {
  color: #999;
  text-align: center;
  padding: 16px 0;
}
@media (max-width: 768px) {
  .page-header {
    padding: 8px 12px;
  }
}
</style>
